package com.xingfly.service;

import com.xingfly.constant.HttpConstant;
import com.xingfly.model.TokenModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.concurrent.TimeUnit;

/**
 * 基于Redis的Token管理
 * Created by SuperS on 19/05/2017.
 *
 * @author SuperS
 */
@Service
public class RedisTokenManager {
    @Autowired
    private RedisTemplate redisTemplate;

    //创建Token
    public TokenModel createToken(Long userId, String sessionID) {
        //拼接(token由userID+当前sessionID组成)
        String token = userId + sessionID;
        //通过MD5加密token字符串
        TokenModel model = new TokenModel(userId, DigestUtils.md5DigestAsHex(token.getBytes()));
        //设置key为userID
        BoundValueOperations<Long, TokenModel> operations = redisTemplate.boundValueOps(userId);
        //将tokenModel序列化到Redis中并且设置过期时长为3小时
        operations.set(model, HttpConstant.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
        return model;
    }

    //获取Token(通过用户传入的token令牌解析成TokenModel对象)
    public TokenModel getToken(String authentication) {
        if (authentication == null || authentication.length() == 0) {
            return null;
        }
        String[] param = authentication.split("_");
        if (param.length != 2) {
            return null;
        }
        Long userId = Long.parseLong(param[0]);
        String token = param[1];
        return new TokenModel(userId, token);
    }

    //检查Token
    public boolean checkToken(TokenModel model, String sessionId) {
        //判断model是否为空
        if (model == null) {
            return false;
        }
        //判断此用户是否已经创建过token
        if (!redisTemplate.hasKey(model.getId())) {
            return false;
        }
        //获取到当前ID的Token
        BoundValueOperations<Long, TokenModel> operations = redisTemplate.boundValueOps(model.getId());
        //获取到TokenModel的Token字符串
        String token = operations.get().getToken();
        //保证Token 只在 唯一的设备上 才能使用。别的设备不能使用该Token
        //拼接一个Token用来验证是否是同一设备产生的Token
        String verifyTokenStr = model.getId() + sessionId;
        //加密这个Token
        String verifyToken = DigestUtils.md5DigestAsHex(verifyTokenStr.getBytes());
        //判断model中的Token和新生成的是否为同一Token(如果一样则设备是相同的、如果不一样则证明不是相同的设备)
        if (token == null || !token.equals(model.getToken()) || !token.equals(verifyToken)) {
            return false;
        }
        // 如果验证成功，说明此用户进行了一次有效操作，延长 token 的过期时间
        operations.expire(HttpConstant.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
        return true;
    }

    //删除Token
    public void deleteToken(long userId) {
        redisTemplate.delete(userId);
    }
}
